from AStock.ASEvent.qthread import QThread
from AStock.ASEvent.task import Task
import time


class Engine(QThread):
    """
    QThread 包含一个线程和一个队列，依次调用队列里的Task任务的do方法
    Engine 继承QThread，还包含一个events字典，维护QThread name和QThread
        对象，可以将Task任务放入bind_event名称相同的QThread线程队列执行，
        也可以直接放入Engine自身的队列，Engine自身的线程会遍历qthreads字典，
        将Task任务放入bind_event名称相同的线程执行
    """

    def __init__(self):
        super(Engine, self).__init__(name='Engine')
        self.__events = {}
        self._idle = True

    def __repr__(self):
        return '<Engine with {} event threads>'.format(
            len(self.__events)
        )

    @property
    def idle(self):
        return self._idle

    def safe_quit(self):
        count = 0
        while True:
            if self.all_idle():
                count += 1
                if count == 10:
                    break
            else:
                count = 0
            time.sleep(1)
        self.stop_all()
        self.join_all()

    def all_idle(self):
        if not self.idle:
            return False
        for _, qthread in self.__events.items():
            if not qthread.idle:
                return False
        return True

    def create_event(self, event_name, daemon=False):
        if event_name not in self.__events:
            self.__events[event_name] = QThread(name=event_name, daemon=daemon)

    def get_event(self, event_name):
        return self.__events.get(event_name)

    def event_num(self):
        return len(self.__events)

    def start_event(self, event_name):
        if event_name in self.__events:
            self.__events[event_name].start()

    def stop_event(self, event_name):
        if event_name in self.__events:
            self.__events[event_name].stop()

    def join_event(self, event_name):
        if event_name in self.__events:
            self.__events[event_name].join()

    def resume_event(self, event_name):
        if event_name in self.__events:
            self.__events[event_name].resume()

    def pause_event(self, event_name):
        if event_name in self.__events:
            self.__events[event_name].pause()

    def run_task(self, task):
        event_name = task.bind_event
        if event_name in self.__events:
            self.__events[event_name].put(task)
        else:
            self.put(task)

    def stop_all(self):
        for _, v in self.__events.items():
            v.stop()
        self.stop()

    def join_all(self):
        for _, v in self.__events.items():
            v.join()
        super(Engine, self).join()

    def run(self):
        while self._running.isSet():
            self._flag.wait()
            try:
                if not self.queue.empty():
                    self._idle = False
                    task = self.queue.get()
                    assert isinstance(task, Task)
                    if task.bind_event in self.__events:
                        self.run_task(task)
                    elif task.worker:
                        # print('thread name: ', self.name)
                        print('event loop: {}, run task: {}'.format(
                            self.name, task.name if task.name else '--'))
                        task.do()
                    self.queue.task_done()
                else:
                    self._idle = True
                    time.sleep(0.01)  # 10ms
            except AssertionError as e:
                print('Thread queue item type error, Task type expected.')
            except Exception as e:
                raise e

